interface SuperType {
  base: string;
}

interface SubType extends SuperType {
  addition: string;
}

let superType: SuperType = {
  base: 'base'
};

let subType:SubType = {
  base: 'myBase',
  addition: 'myAddition',
}

superType = subType;

/**
* Covariant 协变 
* 【更具体】参数类型可以是其派生类型
*/
type Covariant<T> = T[];

let coSuperType: Covariant<SuperType> = [];
let coSubType: Covariant<SubType> = [];

coSuperType = coSubType;
//coSubType = coSuperType; //err: Property 'addition' is missing in type 'SuperType' but required in type 'SubType'.

/**
* Contravariant 逆变
* 【更宽泛】参数类型可以是其基类类型。
*/
//!--strictFunctionTypes true
type Contravariant<T> = (p: T) => void;

let contraSuperType: Contravariant<SuperType> = function(p:SuperType) {};

let contraSubType: Contravariant<SubType> = function(p:SubType) {};

//contraSuperType = contraSubType; //err:Property 'addition' is missing in type 'SuperType' but required in type 'SubType'.
contraSubType  = contraSuperType;

/**
* Bivariant
*/
//!--strictFunctionTypes false
// 双变
type Bivariant<T> = (p: T) => void;

let biSuperType: Bivariant<SuperType> = function(p:SuperType) {};

let biSubType: Bivariant<SubType> = function(p:SubType) {};

// both are ok
biSuperType = biSubType;
biSubType = biSuperType; // 父类子类相互赋值

/**
* Invariant 不变
*/
type Invariant<T> = {
a: Covariant<T>,
b: Contravariant<T>,
}

let inSuperType: Invariant<SuperType> = {
  a: coSuperType,
  b: contraSuperType,
}

let inSubType: Invariant<SubType>  = {
  a: coSubType,
  b: contraSubType,
}

//inSuperType = inSubType; //err
//inSubType = inSuperType; //err
